﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Diggins.Jigsaw;

namespace Domain
{
    public class Grammar : SharedGrammar
    {
        public static Rule RecExpr = Recursive(() => Expr);
        public static Rule RecCom = Recursive(() => Com);

        

        public static Rule True = Node(MatchString("true")); 
        public static Rule False = Node(MatchString("false"));
        public static Rule read = Node(MatchString("read"));

        public new static Rule Integer = Node(SharedGrammar.Integer);

        public new static Rule Identifier = Node(SharedGrammar.Identifier);

        public static Rule prefixOp = Node(MatchString("not"));
        public static Rule binaryOp = Node(MatchStringSet("= +"));

        public static Rule PrefixExpr = Node(prefixOp + Recursive(() => PrefixOrLeafExpr));
        public static Rule ParenExpr = Node(CharToken('(') + WS + RecExpr + WS + CharToken(')'));
        public static Rule LeafExpr = ParenExpr | Integer | True | False | read | Identifier;
        public static Rule PrefixOrLeafExpr = PrefixExpr | LeafExpr;


        public static Rule UnaryExpr = PrefixOrLeafExpr;
        public static Rule BinaryExpr = Node(UnaryExpr + WS + OneOrMore(binaryOp + WS + UnaryExpr + WS));


        public static Rule Expr = Node( read | False | True | Integer | BinaryExpr | UnaryExpr | Identifier);

        public static Rule Block = Node(MatchString("begin") + WS + ZeroOrMore(RecCom + Eos) + WS + MatchString("end"));
        public new static Rule Eq = MatchString(":=");
        public static Rule VarDecl = Node(Identifier + WS + Eq + WS + Expr);
        public static Rule output = Node(MatchString("output") + WS + Expr);
        public static Rule Else = Node(MatchString("else") + WS+ Block);
        public static Rule If = Node(MatchString("if") + WS + ParenExpr + WS + MatchString("then") 
                                   + WS + Block + WS
                                   + Opt(Else));
        public static Rule While = Node(Keyword("while") + WS + ParenExpr + WS + Block);
        public static Rule Com =   While | VarDecl | output | If ;

        public static Rule Program = Node(ZeroOrMore(Com+Eos));

        static Grammar()
        {
            Type tp = typeof(Grammar);
            InitGrammar(tp);
        }

    }
}
